package com.gpagers.kit.lucene.util;

import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.util.ArrayList;
import java.util.List;

import org.apache.lucene.document.Document;
import org.apache.lucene.document.Field;
import org.apache.lucene.document.Field.Store;
import org.apache.lucene.document.StringField;
import org.apache.lucene.document.TextField;
import org.apache.tika.metadata.Metadata;
import org.apache.tika.parser.AutoDetectParser;
import org.apache.tika.parser.ParseContext;
import org.apache.tika.parser.Parser;
import org.apache.tika.parser.microsoft.OfficeParser;
import org.apache.tika.parser.pdf.PDFParser;
import org.apache.tika.sax.BodyContentHandler;
import org.xml.sax.ContentHandler;

import com.gpagers.tools.GlobalConfigHolder;

/**
 * 将文件对象转换为文档对象
 * 
 * 
 */
public class File2Document {
	public static String TEMP_FILE = GlobalConfigHolder.getProperty("tempFile");
	public static String SPLIT_DIR = GlobalConfigHolder.getProperty("splitDir");
	
	public List<Document> file2Document(File file) {
		try {
			String fileTypeStr = file.getName().substring(file.getName().lastIndexOf(".") + 1, file.getName().length());
			// 如果不是txt文件
			if (!fileTypeStr.equals("txt")) {
				parserFile(file);
				return getDocuments(new File(TEMP_FILE), file);
			} else {
				// 如果是txt文件
				return getDocuments(file, null);
			}
		} catch (Exception e) {
			e.printStackTrace();
		}
		return null;
	}

	/**
	 * 将txt文件转换为Document
	 * 
	 * @param file
	 *            txt文件
	 * @return
	 * @throws Exception
	 */
	private List<Document> getDocuments(File newFile, File oldFile) throws Exception {
		List<Document> documents = new ArrayList<Document>();

		if (newFile.length() > 1024) {
			// 将文件分隔成小文件
			split2SmallFiles(newFile, SPLIT_DIR);

			// 遍历所有的小文件，加入Document
			File splitsFile = new File(SPLIT_DIR);
			File[] files = splitsFile.listFiles();
			for (int i = 0; i < files.length; i++) {
				File tempFile = files[i];
				Document document = new Document();
				Field nameField = null;
				Field sizeField = null;
				Field pathField = null;
				if (oldFile == null) {// 如果没有原始文件，说明原来的文件本来就是txt文件
					nameField = new TextField("name", newFile.getName(), Store.YES);
					sizeField = new StringField("size", newFile.length() + "", Store.YES);
					pathField = new StringField("path", newFile.getPath(), Store.YES);
				} else {// 原来的文件不是txt文件，是通过其他文件转换成临时txt文件
					nameField = new TextField("name", oldFile.getName(), Store.YES);
					sizeField = new StringField("size", oldFile.length() + "", Store.YES);
					pathField = new StringField("path", oldFile.getPath(), Store.YES);
				}
				nameField.setBoost(3f);
				document.add(nameField);
				document.add(sizeField);
				document.add(pathField);
				document.add(new TextField("content", readFileContent(tempFile), Store.YES));
				documents.add(document);
			}
			// 将临时产生的小文件删除
			for (File f : files) {
				f.delete();
			}
		} else {
			Document document = new Document();
			Field nameField = null;
			Field sizeField = null;
			Field pathField = null;
			if (oldFile == null) {// 如果没有原始文件，说明原来的文件本来就是txt文件
				nameField = new TextField("name", newFile.getName(), Store.YES);
				sizeField = new StringField("size", newFile.length() + "", Store.YES);
				pathField = new StringField("path", newFile.getPath(), Store.YES);
			} else {// 原来的文件不是txt文件，是通过其他文件转换成临时txt文件
				nameField = new TextField("name", oldFile.getName(), Store.YES);
				sizeField = new StringField("size", oldFile.length() + "", Store.YES);
				pathField = new StringField("path", oldFile.getPath(), Store.YES);
			}
			nameField.setBoost(3f);
			document.add(nameField);
			document.add(sizeField);
			document.add(pathField);
			document.add(new TextField("content", readFileContent(newFile), Store.YES));
			documents.add(document);
		}
		return documents;
	}

	/**
	 * 读取文件内容为String
	 * 
	 * @param file
	 *            需要被读取的文件
	 * @return 文件内容
	 */
	private String readFileContent(File file) throws Exception {
		StringBuilder content = new StringBuilder();
		BufferedReader reader = new BufferedReader(new InputStreamReader(new FileInputStream(file), "UTF-8"));
		String line = "";
		while ((line = reader.readLine()) != null) {
			content.append(line);
		}
		reader.close();
		return content.toString();
	}

	/**
	 * 将文件转换为文本文件并且同意存储到临时文件夹
	 * 
	 * @param inputFile
	 *            要转换的文件
	 * @throws Exception
	 */
	private  void parserFile(File inputFile) throws Exception {
		String fileTypeStr = inputFile.getName().substring(inputFile.getName().lastIndexOf(".") + 1, inputFile.getName().length());
		Parser parser = null;
		if (fileTypeStr.equals("doc")) {
			parser = new OfficeParser();
		} else if (fileTypeStr.equals("pdf")) {
			parser = new PDFParser();
		} else {
			parser = new AutoDetectParser();
		}
		InputStream iStream = new BufferedInputStream(new FileInputStream(inputFile));
		OutputStream oStream = new BufferedOutputStream(new FileOutputStream(new File(TEMP_FILE)));
		ContentHandler iHandler = new BodyContentHandler(oStream);
		Metadata meta = new Metadata();
		meta.add(Metadata.CONTENT_ENCODING, "utf-8");
		parser.parse(iStream, iHandler, meta, new ParseContext());
		iStream.close();
		oStream.close();
	}

	/**
	 * 分隔文件
	 * 
	 * @param file
	 *            要被分隔的文件
	 * @param outputPath
	 *            分割后文件的输出路径
	 * @throws Exception
	 */
	private void split2SmallFiles(File file, String outputPath) throws Exception {
		// 文件计数器
		int filePointer = 0;

		// 定义单个文件的最大长度
		final int MAX_SIZE = 1024000;

		FileOutputStream fos = null;
		FileInputStream fis = new FileInputStream(file);
		byte[] b = new byte[MAX_SIZE];
		int len = 0;
		while ((len = fis.read(b, 0, MAX_SIZE)) != -1) {
			fos = new FileOutputStream(outputPath + "\\" + file.getName().substring(0, file.getName().lastIndexOf(".")) + "_" + filePointer + ".txt");
			fos.write(b, 0, len);
			filePointer++;
		}
		fos.close();
		fis.close();
	}
}
